﻿using System;
using System.Collections.Generic;
using System.Text;

namespace X3DLib
{
    namespace ActionFactor
    {
        public class Action
        {
            public virtual Group createAction()
            {
                Group g = new Group();
                g.addChildren(new Script());
                return g;
            }
            public virtual string getAttrs()
            {
                return "";
            }
            public virtual void setAttrs(string attrs)
            { 
            }
            public virtual string bind2Objec(string obj_name)
            {
                return "";
            }
            public static TimeSensor clock = new TimeSensor("clock_###", "1", "true");
            public static ROUTE route = new ROUTE("fraction_changed", clock.DEF, "start", "control_###");
        }
        /// <summary>
        /// 点2点运动
        /// </summary>
        public class LineAction:Action 
        {
            private string ActionContent;
            private string StartP;

            public string startP
            {
                get { return StartP; }
                set { StartP = value; }
            }
            private string EndP;

            public string endP
            {
                get { return EndP; }
                set { EndP = value; }
            }

            public string actionContent
            {
                get { return ActionContent; }
                set { ActionContent = value; }
            }

            private string Speed;

            public string speed
            {
                get { return Speed; }
                set { Speed = value; }
            }
            public LineAction()
            {
                startP = "0 0 0";
                endP = "1 1 1";
                speed = "5";
                setAttrs("");
            }
            /// <summary>
            /// 完成一个节点从p1到p2变动的脚本控制
            /// </summary>
            public  override Group createAction()
            {
                Group g = new Group();
                g.DEF = "movement_###";
                Script s = new Script();
                s.DEF = "control_###";
                field fld = new field("transform", "SFNode", "inputOutput");
                fld.addChildren(new Transform() { USE = "###" });
                s.addChildren(fld);
                field fldp1 = new field("p1", "SFNode", "inputOutput");
                fldp1.addChildren(new Transform() { translation = startP });
                field fldp2 = new field("p2", "SFNode", "inputOutput");
                fldp2.addChildren(new Transform() { translation = endP });
                s.addChildren(fldp1);
                s.addChildren(fldp2);
                //记录速度
                s.addChildren(new field("velocity", "SFVec3f", "inputOutput"));
                s.addChildren(new field("counter", "SFInt32", "inputOutput"));
                s.addChildren(new field("start", "SFFloat", "inputOutput"));
                string context = "<![CDATA[\njavascript:\n"
                    + "function initialize()\n"
                    + "{\n"
                    + "for(i=0;i<3;i++)\n"
                    + "velocity[i]=p2.translation[i]-p1.translation[i];\n"
                    + "transform.translation=p1.translation;\n"
                    + "}\n"

                    + "function start(value)\n"
                    + "{\n"
                    + "counter++;\n"
                    + "for(i=0;i<3;i++)\n"
                    + "transform.translation[i]+=velocity[i]/"+Double .Parse (speed )+"*0.02;\n"
                    + "if( Math.abs( transform.translation[0])>=Math.abs(p2.translation[0]) )\n"
                    + "initialize();\n"

                    + "}\n"
                        + "\n]]>\n";
                s.addChildren(context);
                g.addChildren(s);
                //add father clock and route
                g.addChildren(clock);
                g.addChildren(route);
                return g;
            }
            public override string bind2Objec(string obj_name)
            {
                return actionContent .Replace ("###",obj_name );
            }
            public override string getAttrs()
            {
                return "startP|" + this.startP  + "|float[3],"
                    + "endP|" + this.endP + "|float[3],"
                    + "speed|" + this.speed + "|float";
            }
            /// <summary>
            /// 设置属性
            /// </summary>
            /// <param name="attrs">字符串格式:"aaaa|bbbb,cccc|dddd,..."</param>
            public override void setAttrs(string attrs)
            {
                string[][] temp = X3DString.getArrayByAttrs(attrs);
                for (int i = 0; i < temp.Length; i++)
                {
                    switch (temp[i][0])
                    {
                        case "startP":
                            this.startP = temp[i][1];
                            break;
                        case "endP":
                            this.endP = temp[i][1];
                            break;
                        case "speed":
                            this.speed  = temp[i][1];
                            break;

                    }
                }
                actionContent = this.createAction().toString();
            }
        }
        /// <summary>
        /// 按函数控制运动
        /// </summary>
        public class FunctionAction : Action
        {
            private string ActionContent;
            private string Functions;
            private string Time;

            public string time
            {
                get { return Time; }
                set { Time = value; }
            }

            public string functions
            {
                get { return Functions; }
                set { Functions = value; }
            }

            public string actionContent
            {
                get { return ActionContent; }
                set { ActionContent = value; }
            }
            public FunctionAction()
            {
                this.functions = "x+=0.02 y+=0.02 z+=0.02";
                this.time = "50";
                setAttrs("");
            }
            /// <summary>
            /// 根据函数方程进行运动
            /// </summary>
            public override Group createAction()
            {
                Group g = new Group();
                g.DEF = "movement_###"; ;
                Script s = new Script();
                s.DEF = "control_###";
                field fld = new field("transform", "SFNode", "inputOutput");
                fld.addChildren(new Transform() { USE = "###" });
                s.addChildren(fld);
                field fldp1 = new field("p1", "SFNode", "inputOutput");
                //记录速度
                s.addChildren(new field("counter", "SFInt32", "inputOutput"));
                s.addChildren(new field("start", "SFFloat", "inputOutput"));
                string context = "<![CDATA[\njavascript:\n"
                    + "function initialize()\n"
                    + "{\n"

                    + "}\n"

                    + "function f_x()\n"
                    + "{\n"
                    + functions.Split(' ')[0].Replace("x", "transform.translation[0]") + ";\n"
                    + "}\n"

                    + "function f_y()\n"
                    + "{\n"

                    + functions.Split(' ')[1].Replace("y", "transform.translation[1]") + ";\n"
                    + "}\n"

                    + "function f_z()\n"
                    + "{\n"
                    + functions.Split(' ')[2].Replace("z", "transform.translation[2]") + ";\n"
                    + "}\n"

                    + "function start(value)\n"
                    + "{\n"
                    + "counter++;\n"
                    + "if(counter<"+Int16.Parse (this.time )+"*50&&counter%50==0)\n"
                    + "{\n"
                    + "f_x();\n"
                    + "f_y();\n"
                    + "f_z();\n"
                    + "}\n"
                    + "}\n"
                        + "\n]]>\n";
                s.addChildren(context);
                g.addChildren(s);
                //add father static clock and route
                g.addChildren(clock);
                g.addChildren(route);
                return g;
            }
            public override string bind2Objec(string obj_name)
            {
                return actionContent.Replace("###", obj_name);
            }
            public override string getAttrs()
            {
                return "functions|" + this.functions + "|f(x) f(y) f(z),"
                        + "time|" + this.time +"|int";
            }
            public override void setAttrs(string attrs)
            {
                string[][] temp = X3DString.getArrayByAttrs(attrs);
                for (int i = 0; i < temp.Length; i++)
                {
                    switch (temp[i][0])
                    {
                        case "functions":
                            this.functions = temp[i][1];
                            break;
                        case "time":
                            this.time = temp[i][1];
                            break;

                    }
                }
                actionContent = this.createAction ().toString();
            }
        }
        /// <summary>
        /// 环绕运动
        /// </summary>
        public class CircleAction :Action
        {
            private string Radius;
            /// <summary>
            /// 环绕半径
            /// </summary>
            public string radius
            {
                get { return Radius; }
                set { Radius = value; }
            }
            private string Center;
            /// <summary>
            /// 环绕中心
            /// </summary>
            public string center
            {
                get { return Center; }
                set { Center = value; }
            }
            private string Speed;
            /// <summary>
            /// 速度
            /// </summary>
            public string speed
            {
                get { return Speed; }
                set { Speed = value; }
            }
            private string ActionContent;
            /// <summary>
            /// 运动数据
            /// </summary>
            public string actionContent
            {
                get { return ActionContent; }
                set { ActionContent = value; }
            }
            public CircleAction()
            {
                this.center = "0 0 0";
                this.radius = "2";
                this.speed = "50";
                this .setAttrs ("");
            }

            public override Group createAction()
            {
                Group g = new Group();
                g.DEF = "movement_###";
                Script s = new Script();
                s.DEF = "control_###";
                field fld = new field("transform", "SFNode", "inputOutput");
                fld.addChildren(new Transform() { USE = "###" });
                s.addChildren(fld);
                //记录速度
                s.addChildren(new field("counter", "SFInt32", "inputOutput"));
                s.addChildren(new field("start", "SFFloat", "inputOutput"));
                string context = "<![CDATA[\njavascript:\n"
                    + "function initialize()\n"
                    + "{\n"
                    + "transform.translation[0]=" + this.radius + ";\n"
                    + "transform.translation[1]=" + 0 + ";\n"
                    + "transform.translation[2]=" + 0 + ";\n"
                    + "}\n"

                    + "function start(value)\n"
                    + "{\n"
                    + " w=" + Double.Parse (this.speed) + "/" + this.radius + ";\n"
                    + "counter++;\n"
                    + "transform.translation[0]=" + this.radius + "*Math.cos(w*counter*0.02/Math.PI);\n"
                    + "transform.translation[1]=0;\n"
                    + "transform.translation[2]=" + this.radius + "*Math.sin(w*counter*0.02/Math.PI);\n"
                    + "}\n"
                    + "\n]]>\n";
                s.addChildren(context);
                g.addChildren(s);
                //add father clock and route
                g.addChildren(clock);
                g.addChildren(route);
                return g;
            }

            public override string bind2Objec(string obj_name)
            {
                return this.actionContent .Replace ("###",obj_name );
            }
            public override string getAttrs()
            {
                return "radius|" + this.radius + "|float,"
                        + "center|" + this.center + "|float[3],"
                        + "speed|" + this.speed + "|float";
            }
            public override void setAttrs(string attrs)
            {
                string[][] temp = X3DString.getArrayByAttrs(attrs);
                for (int i = 0; i < temp.Length; i++)
                {
                    switch (temp[i][0])
                    {
                        case "center":
                            this.center = temp[i][1];
                            break;
                        case "radius":
                            this.radius = temp[i][1];
                            break;
                        case "speed":
                            this.speed = temp[i][1];
                            break;

                    }
                }
                actionContent = this.createAction().toString();
            }
        }
        /// <summary>
        /// 旋转运动
        /// </summary>
        public class RotateAction : Action
        {
            private string Direction;
            /// <summary>
            /// 方向
            /// </summary>
            public string direction
            {
                get { return Direction; }
                set { Direction = value; }
            }
            private string Speed;
            /// <summary>
            /// 速度
            /// </summary>
            public string speed
            {
                get { return Speed; }
                set { Speed = value; }
            }
            private string Time;
            /// <summary>
            /// 时间
            /// </summary>
            public string time
            {
                get { return Time; }
                set { Time = value; }
            }
            private string ActionContent;
            /// <summary>
            /// 运动数据
            /// </summary>
            public string actionContent
            {
                get { return ActionContent; }
                set { ActionContent = value; }
            }
            public RotateAction()
            {
                this.direction = "1 0 0";
                this.speed = "0.1";
                this.time = "100";
                this.setAttrs("");
            }
            public override Group createAction()
            {
                Group g = new Group();
                g.DEF = "movement_###";
                Script s = new Script();
                s.DEF = "control_###";
                field fld = new field("transform", "SFNode", "inputOutput");
                fld.addChildren(new Transform() { USE = "###" });
                s.addChildren(fld);
                //记录时间
                s.addChildren(new field("counter", "SFInt32", "inputOutput"));
                s.addChildren(new field("start", "SFFloat", "inputOutput"));
                string context = "<![CDATA[\njavascript:\n"
                    + "function initialize()\n"
                    + "{\n"
                    + "transform.rotation[0]=" + this .direction .Split (' ')[0] + ";\n"
                    + "transform.rotation[1]=" + this .direction .Split (' ')[1] + ";\n"
                    + "transform.rotation[2]=" + this .direction .Split (' ')[2] + ";\n"
                    + "}\n"

                    + "function start(value)\n"
                    + "{\n"
                    + "counter++;\n"
                    +"if(counter<"+this.time +")\n"
                    + "transform.rotation[3]="+this .speed +"*counter;\n"
                    + "}\n"
                    + "\n]]>\n";
                s.addChildren(context);
                g.addChildren(s);
                //add father clock and route
                g.addChildren(clock);
                g.addChildren(route);
                return g;
            }
            public override string getAttrs()
            {
                return "direction|"+this.direction +"|min:0 max:1 float[3],"
                    +"speed|"+this .speed +"|float,"
                    +"time|"+this.time +"|float";
            }
            public override void setAttrs(string attrs)
            {
                string[][] temp = X3DString.getArrayByAttrs(attrs);
                for (int i = 0; i < temp.Length; i++)
                {
                    switch (temp[i][0])
                    {
                        case "direction":
                            this.direction = temp[i][1];
                            break;
                        case "speed":
                            this.speed = temp[i][1];
                            break;
                        case "time":
                            this.time = temp[i][1];
                            break;

                    }
                }
                actionContent = this.createAction().toString();
            }
            public override string bind2Objec(string obj_name)
            {
                return this.actionContent .Replace ("###",obj_name );
            }
        }
    }
}
